package io.github.echarts.render.svg;

import io.github.echarts.render.GraphicsRenderer;

import java.awt.Color;
import java.awt.Font;
import java.awt.geom.Path2D;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * SVG渲染器实现，将图形渲染为SVG格式
 * 注意：所有坐标在接口中使用左下角为原点(0,0)的逻辑坐标系，在内部转换为SVG使用的左上角为原点的坐标系
 */
public class SVGRenderer implements GraphicsRenderer {
    
    /**
     * SVG文档
     */
    private Document document;
    
    /**
     * SVG根元素
     */
    private Element svgRoot;
    
    /**
     * 图层元素映射表
     */
    private Map<String, Element> layerElements;
    
    /**
     * 当前图层类型
     */
    private String currentLayer;
    
    /**
     * 画布宽度
     */
    private int canvasWidth;
    
    /**
     * 画布高度
     */
    private int canvasHeight;
    
    /**
     * 创建SVG渲染器
     */
    public SVGRenderer() {
        layerElements = new HashMap<>();
        currentLayer = SVGLayerType.SERIES; // 默认使用系列图层
    }
    
    @Override
    public void beginRender(int width, int height) {
        try {
            // 创建SVG文档
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();
            document = builder.newDocument();
            
            // 创建SVG根元素
            svgRoot = document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_ELEMENT);
            svgRoot.setAttributeNS(null, "version", SVGConstants.SVG_VERSION);
            svgRoot.setAttributeNS(null, SVGConstants.WIDTH_ATTRIBUTE, String.valueOf(width));
            svgRoot.setAttributeNS(null, SVGConstants.HEIGHT_ATTRIBUTE, String.valueOf(height));
            document.appendChild(svgRoot);
            
            // 记录画布尺寸（用于坐标转换）
            this.canvasWidth = width;
            this.canvasHeight = height;
            
            // 创建图层元素
            createLayers();
            
        } catch (ParserConfigurationException e) {
            throw new RuntimeException("Failed to initialize SVG document", e);
        }
    }
    
    /**
     * 创建所有图层元素
     */
    private void createLayers() {
        // 按照从底层到顶层的顺序创建图层
        for (String layerType : SVGLayerType.getAllLayersInOrder()) {
            Element layer = document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.G_ELEMENT);
            layer.setAttributeNS(null, SVGConstants.ID_ATTRIBUTE, "layer-" + layerType);
            layer.setAttributeNS(null, SVGConstants.CLASS_ATTRIBUTE, "echarts-layer " + layerType);
            svgRoot.appendChild(layer);
            layerElements.put(layerType, layer);
        }
    }
    
    @Override
    public String endRender() {
        try {
            // 将SVG文档转换为字符串
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
            
            StringWriter writer = new StringWriter();
            transformer.transform(new DOMSource(document), new StreamResult(writer));
            
            return writer.toString();
        } catch (TransformerException e) {
            throw new RuntimeException("Failed to serialize SVG document", e);
        }
    }
    
    @Override
    public void setCurrentLayer(String layerType) {
        // 确保图层存在，如果不存在就使用默认图层
        if (!layerElements.containsKey(layerType)) {
            this.currentLayer = SVGLayerType.SERIES;
        } else {
            this.currentLayer = layerType;
        }
    }
    
    @Override
    public String getCurrentLayer() {
        return currentLayer;
    }
    
    /**
     * 获取当前图层元素
     * 
     * @return 当前图层元素
     */
    private Element getCurrentLayerElement() {
        return layerElements.get(currentLayer);
    }
    
    /**
     * 转换Y坐标，从左下角原点转换为左上角原点
     * 
     * @param y 基于左下角原点的Y坐标
     * @return 基于左上角原点的Y坐标
     */
    private int transformY(int y) {
        return canvasHeight - y;
    }
    
    /**
     * 转换Y坐标，从左下角原点转换为左上角原点，支持double类型
     * 
     * @param y 基于左下角原点的Y坐标
     * @return 基于左上角原点的Y坐标
     */
    private double transformY(double y) {
        return canvasHeight - y;
    }
    
    @Override
    public void drawRect(int x, int y, int width, int height, boolean fill, String fillColor, String strokeColor) {
        // 坐标转换（左下角原点 -> 左上角原点）
        // 在逻辑坐标系中，矩形的起点是左下角，需要转换为SVG的左上角起点
        int svgY = transformY(y + height);  // 转换Y坐标
        
        Element rect = document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.RECT_ELEMENT);
        rect.setAttributeNS(null, SVGConstants.X_ATTRIBUTE, String.valueOf(x));
        rect.setAttributeNS(null, SVGConstants.Y_ATTRIBUTE, String.valueOf(svgY));
        rect.setAttributeNS(null, SVGConstants.WIDTH_ATTRIBUTE, String.valueOf(width));
        rect.setAttributeNS(null, SVGConstants.HEIGHT_ATTRIBUTE, String.valueOf(height));
        
        if (fill && fillColor != null) {
            rect.setAttributeNS(null, SVGConstants.FILL_ATTRIBUTE, fillColor);
        } else {
            rect.setAttributeNS(null, SVGConstants.FILL_ATTRIBUTE, "none");
        }
        
        if (strokeColor != null) {
            rect.setAttributeNS(null, SVGConstants.STROKE_ATTRIBUTE, strokeColor);
            rect.setAttributeNS(null, SVGConstants.STROKE_WIDTH_ATTRIBUTE, "1");
        }
        
        getCurrentLayerElement().appendChild(rect);
    }
    
    @Override
    public void fillPath(Path2D path, String fillColor) {
        // 使用PathUtil转换路径数据，并处理坐标转换
        String pathData = PathUtil.convertToSVGPath(path, canvasHeight);
        if (pathData.isEmpty()) {
            return; // 如果路径为空，不进行渲染
        }
        
        Element pathElement = document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.PATH_ELEMENT);
        pathElement.setAttributeNS(null, SVGConstants.D_ATTRIBUTE, pathData);
        pathElement.setAttributeNS(null, SVGConstants.FILL_ATTRIBUTE, fillColor != null ? fillColor : "#000");
        pathElement.setAttributeNS(null, SVGConstants.STROKE_ATTRIBUTE, "none");
        
        getCurrentLayerElement().appendChild(pathElement);
    }
    
    @Override
    public void drawCircle(int cx, int cy, int radius, boolean fill, String fillColor, String strokeColor) {
        // 坐标转换（左下角原点 -> 左上角原点）
        int svgCy = transformY(cy);
        
        Element circle = document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.CIRCLE_ELEMENT);
        circle.setAttributeNS(null, SVGConstants.CX_ATTRIBUTE, String.valueOf(cx));
        circle.setAttributeNS(null, SVGConstants.CY_ATTRIBUTE, String.valueOf(svgCy));
        circle.setAttributeNS(null, SVGConstants.R_ATTRIBUTE, String.valueOf(radius));
        
        if (fill && fillColor != null) {
            circle.setAttributeNS(null, SVGConstants.FILL_ATTRIBUTE, fillColor);
        } else {
            circle.setAttributeNS(null, SVGConstants.FILL_ATTRIBUTE, "none");
        }
        
        if (strokeColor != null) {
            circle.setAttributeNS(null, SVGConstants.STROKE_ATTRIBUTE, strokeColor);
            circle.setAttributeNS(null, SVGConstants.STROKE_WIDTH_ATTRIBUTE, "1");
        }
        
        getCurrentLayerElement().appendChild(circle);
    }
    
    @Override
    public void drawSector(int cx, int cy, int innerRadius, int outerRadius, 
            double startAngle, double endAngle, boolean fill, String fillColor, String strokeColor) {
        // 坐标转换（左下角原点 -> 左上角原点）
        int svgCy = transformY(cy);
        
        // 在SVG中绘制扇形需要使用路径
        // 计算扇形的路径数据
        // 注意：在Y轴翻转后，角度方向也需要调整
        double adjustedStartAngle = -endAngle;   // 角度反转
        double adjustedEndAngle = -startAngle;   // 角度反转
        
        // 计算路径点
        double x1 = cx + outerRadius * Math.cos(adjustedStartAngle);
        double y1 = svgCy + outerRadius * Math.sin(adjustedStartAngle);
        double x2 = cx + outerRadius * Math.cos(adjustedEndAngle);
        double y2 = svgCy + outerRadius * Math.sin(adjustedEndAngle);
        
        int largeArcFlag = Math.abs(endAngle - startAngle) > Math.PI ? 1 : 0;
        
        StringBuilder pathData = new StringBuilder();
        
        if (innerRadius > 0) {
            // 有内半径，绘制环形扇区
            double x3 = cx + innerRadius * Math.cos(adjustedEndAngle);
            double y3 = svgCy + innerRadius * Math.sin(adjustedEndAngle);
            double x4 = cx + innerRadius * Math.cos(adjustedStartAngle);
            double y4 = svgCy + innerRadius * Math.sin(adjustedStartAngle);
            
            pathData.append("M").append(x1).append(",").append(y1)
                   .append(" A").append(outerRadius).append(",").append(outerRadius)
                   .append(" 0 ").append(largeArcFlag).append(" 0 ")
                   .append(x2).append(",").append(y2)
                   .append(" L").append(x3).append(",").append(y3)
                   .append(" A").append(innerRadius).append(",").append(innerRadius)
                   .append(" 0 ").append(largeArcFlag).append(" 1 ")
                   .append(x4).append(",").append(y4)
                   .append(" Z");
        } else {
            // 无内半径，绘制普通扇形
            pathData.append("M").append(cx).append(",").append(svgCy)
                   .append(" L").append(x1).append(",").append(y1)
                   .append(" A").append(outerRadius).append(",").append(outerRadius)
                   .append(" 0 ").append(largeArcFlag).append(" 0 ")
                   .append(x2).append(",").append(y2)
                   .append(" Z");
        }
        
        Element path = document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.PATH_ELEMENT);
        path.setAttributeNS(null, SVGConstants.D_ATTRIBUTE, pathData.toString());
        
        if (fill && fillColor != null) {
            path.setAttributeNS(null, SVGConstants.FILL_ATTRIBUTE, fillColor);
        } else {
            path.setAttributeNS(null, SVGConstants.FILL_ATTRIBUTE, "none");
        }
        
        if (strokeColor != null) {
            path.setAttributeNS(null, SVGConstants.STROKE_ATTRIBUTE, strokeColor);
            path.setAttributeNS(null, SVGConstants.STROKE_WIDTH_ATTRIBUTE, "1");
        }
        
        getCurrentLayerElement().appendChild(path);
    }
    
    @Override
    public void drawGridLine(int x1, int y1, int x2, int y2, String color, int width, String type) {
        // 坐标转换（左下角原点 -> 左上角原点）
        int svgY1 = transformY(y1);
        int svgY2 = transformY(y2);
        
        Element line = document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.LINE_ELEMENT);
        line.setAttributeNS(null, SVGConstants.X1_ATTRIBUTE, String.valueOf(x1));
        line.setAttributeNS(null, SVGConstants.Y1_ATTRIBUTE, String.valueOf(svgY1));
        line.setAttributeNS(null, SVGConstants.X2_ATTRIBUTE, String.valueOf(x2));
        line.setAttributeNS(null, SVGConstants.Y2_ATTRIBUTE, String.valueOf(svgY2));
        line.setAttributeNS(null, SVGConstants.STROKE_ATTRIBUTE, color);
        line.setAttributeNS(null, SVGConstants.STROKE_WIDTH_ATTRIBUTE, String.valueOf(width));
        
        // 设置线型
        if ("dashed".equals(type)) {
            line.setAttributeNS(null, SVGConstants.STROKE_DASHARRAY_ATTRIBUTE, "5,5");
        } else if ("dotted".equals(type)) {
            line.setAttributeNS(null, SVGConstants.STROKE_DASHARRAY_ATTRIBUTE, "2,2");
        }
        
        // 确保网格线添加到网格图层
        layerElements.get(SVGLayerType.GRID).appendChild(line);
    }
    
    @Override
    public void drawTrapezoid(int x, int y, int topWidth, int bottomWidth, int height,
            boolean fill, String fillColor, String strokeColor) {
        // 坐标转换（左下角原点 -> 左上角原点）
        // 在逻辑坐标系中，y是底边的y坐标，转换为SVG坐标系中的顶边y坐标
        int svgY = transformY(y + height);
        
        // 计算梯形的四个顶点（SVG坐标系中，从顶部顶点开始，顺时针）
        int halfTopWidth = topWidth / 2;
        int halfBottomWidth = bottomWidth / 2;
        
        String points = 
                (x - halfTopWidth) + "," + svgY + " " +                  // 左上
                (x + halfTopWidth) + "," + svgY + " " +                  // 右上
                (x + halfBottomWidth) + "," + (svgY + height) + " " +    // 右下
                (x - halfBottomWidth) + "," + (svgY + height);           // 左下
        
        Element polygon = document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.POLYGON_ELEMENT);
        polygon.setAttributeNS(null, SVGConstants.POINTS_ATTRIBUTE, points);
        
        if (fill && fillColor != null) {
            polygon.setAttributeNS(null, SVGConstants.FILL_ATTRIBUTE, fillColor);
        } else {
            polygon.setAttributeNS(null, SVGConstants.FILL_ATTRIBUTE, "none");
        }
        
        if (strokeColor != null) {
            polygon.setAttributeNS(null, SVGConstants.STROKE_ATTRIBUTE, strokeColor);
            polygon.setAttributeNS(null, SVGConstants.STROKE_WIDTH_ATTRIBUTE, "1");
        }
        
        getCurrentLayerElement().appendChild(polygon);
    }
    
    @Override
    public void drawLine(int x1, int y1, int x2, int y2, String color, int width, String type) {
        // 坐标转换（左下角原点 -> 左上角原点）
        int svgY1 = transformY(y1);
        int svgY2 = transformY(y2);
        
        Element line = document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.LINE_ELEMENT);
        line.setAttributeNS(null, SVGConstants.X1_ATTRIBUTE, String.valueOf(x1));
        line.setAttributeNS(null, SVGConstants.Y1_ATTRIBUTE, String.valueOf(svgY1));
        line.setAttributeNS(null, SVGConstants.X2_ATTRIBUTE, String.valueOf(x2));
        line.setAttributeNS(null, SVGConstants.Y2_ATTRIBUTE, String.valueOf(svgY2));
        line.setAttributeNS(null, SVGConstants.STROKE_ATTRIBUTE, color);
        line.setAttributeNS(null, SVGConstants.STROKE_WIDTH_ATTRIBUTE, String.valueOf(width));
        
        // 设置线型
        if ("dashed".equals(type)) {
            line.setAttributeNS(null, SVGConstants.STROKE_DASHARRAY_ATTRIBUTE, "5,5");
        } else if ("dotted".equals(type)) {
            line.setAttributeNS(null, SVGConstants.STROKE_DASHARRAY_ATTRIBUTE, "2,2");
        }
        
        getCurrentLayerElement().appendChild(line);
    }
    
    @Override
    public void drawText(String text, int x, int y, Font font, String color, String align) {
        // 坐标转换（左下角原点 -> 左上角原点）
        int svgY = transformY(y);
        
        Element textElement = document.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.TEXT_ELEMENT);
        textElement.setAttributeNS(null, SVGConstants.X_ATTRIBUTE, String.valueOf(x));
        textElement.setAttributeNS(null, SVGConstants.Y_ATTRIBUTE, String.valueOf(svgY));
        
        // 设置对齐方式
        String textAnchor = "middle"; // 默认居中
        if ("left".equals(align)) {
            textAnchor = "start";
        } else if ("right".equals(align)) {
            textAnchor = "end";
        }
        textElement.setAttributeNS(null, SVGConstants.TEXT_ANCHOR_ATTRIBUTE, textAnchor);
        
        // 设置基线对齐
        textElement.setAttributeNS(null, SVGConstants.DOMINANT_BASELINE_ATTRIBUTE, "central");
        
        // 设置字体样式
        if (font != null) {
            // 设置内联样式
            StringBuilder styleValue = new StringBuilder();
            
            // 字体相关样式
            if (font.isBold()) {
                styleValue.append("font-weight:bold;");
            }
            if (font.isItalic()) {
                styleValue.append("font-style:italic;");
            }
            styleValue.append("font-size:").append(font.getSize()).append("px;");
            styleValue.append("font-family:").append(font.getFamily()).append(";");
            
            // 设置内联样式
            textElement.setAttributeNS(null, SVGConstants.STYLE_ATTRIBUTE, styleValue.toString());
            
            // 单独设置字体属性（以确保兼容性）
            textElement.setAttributeNS(null, SVGConstants.FONT_FAMILY_ATTRIBUTE, font.getFamily());
            textElement.setAttributeNS(null, SVGConstants.FONT_SIZE_ATTRIBUTE, font.getSize() + "px");
            
            if (font.isBold()) {
                textElement.setAttributeNS(null, SVGConstants.FONT_WEIGHT_ATTRIBUTE, "bold");
            }
        } else {
            // 默认字体
            textElement.setAttributeNS(null, SVGConstants.FONT_FAMILY_ATTRIBUTE, "Arial");
            textElement.setAttributeNS(null, SVGConstants.FONT_SIZE_ATTRIBUTE, "12px");
        }
        
        // 设置颜色
        textElement.setAttributeNS(null, SVGConstants.FILL_ATTRIBUTE, color != null ? color : "#000000");
        
        // 添加文本内容
        textElement.appendChild(document.createTextNode(text != null ? text : ""));
        
        // 将文本添加到当前图层
        getCurrentLayerElement().appendChild(textElement);
    }
} 